﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockFinder.Model;

namespace StockFinder.Services.ChartPatterns
{
    /// <summary>
    /// Weekly close price from 7 weeks ago must be 7 week high; correction must be no
    /// more than 35%
    /// </summary>
    public class WeeklyCupWithHandleBaseChartPattern : IChartPattern
    {
        private readonly decimal _MaximumBaseDepth = 0.35M;
        private readonly decimal _MinimumBaseDepth = 0.15M;
        private readonly int _MinimumWeeklyCoverage = 7;

        public WeeklyCupWithHandleBaseChartPattern()
        {
            //use defaults
        }

        public WeeklyCupWithHandleBaseChartPattern(decimal baseDepth, int minimumWeeklyCoverage)
        {
            _MaximumBaseDepth = baseDepth;
            _MinimumWeeklyCoverage = minimumWeeklyCoverage;
        }

        #region IChartPattern Members

        public ChartPatternResult Apply(Symbol symbol)
        {
            ChartPatternResult result = new ChartPatternResult();

            result.Symbol = symbol;
            result.DoesFit = false;

            //check there are enough weekly prices
            if (symbol.WeeklyPrices.Count > _MinimumWeeklyCoverage)
            {
                //set first week prices
                decimal lowestPriceInBase = symbol.WeeklyPrices[0].GetWeeklyLow();
                decimal highestPriceInBase = symbol.WeeklyPrices[0].GetWeeklyHigh();
                WeeklyPrice highestWeek = null;
                WeeklyPrice lowestWeek = null;
                int highestWeekCount = 0;
                int lowestWeekIndex = 0;

                //loop prices
                for (int weekCount = 1; weekCount < _MinimumWeeklyCoverage; weekCount++)
                {
                    //is this a new low price?
                    if (symbol.WeeklyPrices[weekCount].GetWeeklyLow() < lowestPriceInBase)
                    {
                        lowestPriceInBase = symbol.WeeklyPrices[weekCount].GetWeeklyLow();

                        lowestWeek = symbol.WeeklyPrices[weekCount];

                        lowestWeekIndex = weekCount;
                    }

                    //is this a new high price?
                    if (symbol.WeeklyPrices[weekCount].GetWeeklyHigh() > highestPriceInBase)
                    {
                        highestPriceInBase = symbol.WeeklyPrices[weekCount].GetWeeklyHigh();

                        highestWeekCount = weekCount;

                        highestWeek = symbol.WeeklyPrices[weekCount];
                    }
                }

                //get the base start week
                WeeklyPrice baseStartWeek = symbol.WeeklyPrices[_MinimumWeeklyCoverage];

                //get the potential breakpoint
                decimal breakPoint = baseStartWeek.GetWeeklyHigh();  
                
                //1. breakpoint must be highest point i.e. price hasnt been reached for weekly coverage
                if (breakPoint > highestPriceInBase)
                {
                    //2. depth must be within range
                    //work out base depth
                    decimal depth = (breakPoint - lowestPriceInBase) / breakPoint;

                    //is the base within the criteria?
                    if (depth > _MinimumBaseDepth && depth <= _MaximumBaseDepth)
                    {
                        result.DoesFit = true;
                    }                
                }            
            }

            return result;
        }

        #endregion
    }
}
